using SqlSugar;
using IM.Easy.Core.Services;
using IM.Easy.Core.Utils;
using IM.Easy.Infrastructure.Query;
using IM.Easy.Core.Extensions;
using IM.Easy.Entity.System;
using IM.Easy.SystemServices.Dtos;
using IM.Easy.SystemServices.IServices;
using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
using IM.Easy.Infrastructure.Constants;
using Microsoft.AspNetCore.Hosting;
using IM.Easy.CoreServices.IServices;
using System.Security.Cryptography;

namespace IM.Easy.SystemServices.Services
{
    public class FileResourceService : AppServices<FileResource>, IFileResourceService
    {
        private readonly IWebHostEnvironment _env;
        private readonly IParamsService _paramsService;
        public FileResourceService(ISqlSugarClient db, IWebHostEnvironment env, IParamsService paramsService) : base(db)
        {
            _env = env;
            _paramsService = paramsService;
        }

        public FileResource Create(FileResource entity)
        {
            // TODO: 添加创建逻辑
            return Context.Insertable(entity).ExecuteReturnEntity();
        }

        /// <summary>
        /// 获取文件明细信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public FileResourceDto GetById(Guid id)
        {
            var resource = Context.Queryable<FileResource>()
                .LeftJoin<FileTypes>((fr, ft) => fr.Mime == ft.MimeType)
                .Select((fr, ft) => new FileResourceDto { Icon = ft.Icon, Type = ft.Group }, true)
                .Where((fr) => fr.Id == id)
                .First();
            resource.Url = MapToNetworkUrl(resource.FilePath);
            return resource;
        }

        public PageResponse<FileResource> GetPageList(FileResourceQueryDto query)
        {
            var queryable = Context.Queryable<FileResource>();
            var exp = Expressionable.Create<FileResource>();
            exp = exp
;
            var page = queryable
                 .Where(exp.ToExpression())
                 .ToPageList<FileResource, FileResource>(query);
            return page;
        }

        public bool Update(FileResource entity)
        {
            // TODO: 添加更新逻辑
            return Context.Updateable(entity).ExecuteCommandHasChange();
        }

        /// <summary>
        ///  List<string>
        /// </summary>
        /// <param name="Id"></param>
        /// <returns>返回物理存储地址</returns>
        public List<string> Delete(params Guid[] Id)
        {
            var files = Context.Queryable<FileResource>()
                                .In(Id)
                                .ToList();
            var physicalPath = files.Select(s => s.FilePath).ToList();
            base.Delete(files);
            return physicalPath;
        }

        /// <summary>
        /// 通过文件夹id删除文件 数据库数据
        /// </summary>
        /// <param name="fid"></param>
        /// <returns>返回物理存储地址</returns>
        public List<string> DeleteByFolder(Guid fid)
        {
            var files = Context.Queryable<FileResource>()
                            .Where(s => s.FolderId == fid)
                            .ToList();
            base.Delete(files);
            var storePath = files.Select(s => s.FilePath).ToList();
            return storePath;
        }

        /// <summary>
        /// 删除文件    物理存储数据
        /// </summary>
        /// <param name="path"></param>
        public void DeleteStorage(params string[] path)
        {
            if (path == null || path.Length == 0)
            {
                return;
            }
            // 使用并行任务来删除文件，提高效率
            Parallel.ForEach(path, currentPath =>
            {
                try
                {
                    if (File.Exists(currentPath))
                    {
                        File.Delete(currentPath);
                        Console.WriteLine($"文件 {currentPath} 删除成功。");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"删除文件 {currentPath} 时发生未知错误: {ex.Message}");
                }
            });
        }

        /// <summary>
        /// 存储文件到服务器
        /// </summary>
        /// <param name="file"></param>
        /// <param name="folder"></param>
        /// <returns></returns>
        public async Task<string> LocalStorage(IFormFile file, params string[] folder)
        {
            var dynamicPath = folder.Length > 0 ? Path.Combine(folder) : FileProviderConstants.DynamicStorageRoot;
            var fullFolder = Path.Combine(_env.ContentRootPath, dynamicPath);
            if (!Directory.Exists(fullFolder))
            {
                Directory.CreateDirectory(fullFolder);
            }

            // 生成存储文件名（这里直接使用上传的文件名，可以根据需要加上唯一标识符避免重复）
            var fileName = Path.GetFileName(file.FileName);
            var extension = Path.GetExtension(file.FileName);
            var newFileName = $"{Guid.NewGuid()}{extension}";
            var filePath = Path.Combine(fullFolder, newFileName);

            // 保存文件到服务器
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await file.CopyToAsync(stream);
            }

            return filePath;
        }

        /// <summary>
        /// 将本地资源文件路径映射为静态资源的网络地址
        /// </summary>
        /// <param name="path">本地文件路径（例如：D:\upload\a.jpg）</param>
        /// <returns>静态资源的网络地址，例如 /static/upload/a.jpg</returns>
        public string MapToNetworkUrl(string path)
        {
            var accessUrl = string.Empty;
            if (string.IsNullOrWhiteSpace(path)) return accessUrl;


            var serverHost = _paramsService.GetValue(ParamsConstant.ServerHost);
            // 统一路径格式（转换为绝对路径 & 统一使用 /）
            path = NormalizePath(path);

            // 计算静态资源和动态资源的根目录
            var staticRoot = NormalizePath(_env.WebRootPath);
            var dynamicRoot = NormalizePath(Path.Combine(_env.ContentRootPath, FileProviderConstants.DynamicStorageRoot));

            // 尝试匹配静态或动态资源目录
            if (path.StartsWith(staticRoot, StringComparison.OrdinalIgnoreCase))
            {
                accessUrl = BuildResourceUrl(FileProviderConstants.StaticResourceRequestRoot, staticRoot, path);
            }
            else if (path.StartsWith(dynamicRoot, StringComparison.OrdinalIgnoreCase))
            {
                accessUrl = BuildResourceUrl(FileProviderConstants.DynamicResourceRequestRoot, dynamicRoot, path);
            }
            accessUrl = serverHost + accessUrl;
            return accessUrl;
        }

        /// <summary>
        /// 规范化路径，转换 `\` 为 `/`，去除末尾 `/`
        /// </summary>
        private string NormalizePath(string path)
        {
            return Path.GetFullPath(path).Replace("\\", "/").TrimEnd('/');
        }

        /// <summary>
        /// 计算相对路径并构建资源 URL
        /// </summary>
        private string BuildResourceUrl(string baseUrl, string rootPath, string fullPath)
        {
            var relativePath = Path.GetRelativePath(rootPath, fullPath).Replace("\\", "/").TrimStart('/');
            return $"{baseUrl}/{relativePath}";
        }

        /// <summary>
        /// 重命名
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool Rename(Guid id, string name)
        {
            if (!NameValidate(name, out string errorMsg))
            {
                ExceptionUtils.ThrowBusinessException(errorMsg);
            }
            var file = base.GetById(id);

            var duplicate = IsAny(s => s.FolderId == file.FolderId && name == s.FileName);
            if (duplicate) ExceptionUtils.ThrowBusinessException("文件命名重复");
            file.FileName = name;
            Context.Updateable(file)
                .UpdateColumns(s => s.FileName)
                .ExecuteCommandHasChange();
            return true;
        }

        /// <summary>
        /// 文件夹命名合法性校验
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool NameValidate(string name, out string errorMessage)
        {
            int maxLength = 50;
            if (string.IsNullOrWhiteSpace(name))
            {
                errorMessage = "名称不能为空";
                return false;
            }

            if (name.Length > maxLength)
            {
                errorMessage = $"名称过长，建议{maxLength}个字符内";
                return false;
            }

            // 初始化错误信息为空
            errorMessage = string.Empty;
            // 获取不允许出现在文件名中的字符数组
            char[] invalidChars = Path.GetInvalidFileNameChars();

            // 使用 LINQ 检查名称中是否包含不允许的字符
            if (name.IndexOfAny(invalidChars) != -1)
            {
                string invalidCharList = string.Join(", ", invalidChars.Select(c => $"'{c}'"));
                errorMessage = $"文件名称包含不允许的字符: {invalidCharList}。";
                return false;
            }

            // 所有检查都通过，名称合法
            return true;
        }

    }
}
